package gss.generator;

import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;

import gss.LineSegment;
import gss.Vertex;
import static gss.generator.GeneratorUtils.*;

public class SegmentGenerator {
    /** A collection of LineSegments */
    private static List<LineSegment> linesegs
	= new ArrayList<LineSegment>();
    /** A set of vertices with distinct coordinates */
    private static Map<Vertex, HashSet<LineSegment> > intersections
	= new HashMap<Vertex, HashSet<LineSegment> >();
    /**
     * list view of the vertices 
     * Must be kept in sync with intersections! Use addVertex to
     * ensure this.
     */
    private static List<Vertex> intersectionsList = new ArrayList<Vertex>();

    // output file names
    private static String gssFile;
    private static String matrixFile;
    private static String vertexFile;


    private static int segnum = 20;
    private static int gridsize = segnum;

    // probabilities to call various line segment generation methods
    private static double probRandomSeg = .6;
    private static double probVertexToVertex = .2;
    // probability to extend line segments for the
    // vertexToVertex and randomVertexToRandom methods
    private static double probExtend = .4;

    /**
     * @param args
     */	
    public static void main(String[] args) {
	// parse command line arguments (8):
	//   segnum gridsize
	//   probRandomSeg probVertexToVertex probExtend
	//   gssFile matrixFile verticesFile
	if (args.length < 8) {
	    System.err.println("Incorrect number of arguments.");
	    System.err.println("Arguments: segnum gridsize"
		    + " probRandomSeg probVertexToVertex probExtend"
		    + " gssFile matrixFile intersectionFile");
	    System.exit(1);
	} else {
	    segnum = Integer.parseInt(args[0]);
	    gridsize = Integer.parseInt(args[1]);
	    probRandomSeg = Double.parseDouble(args[2]);
	    probVertexToVertex = Double.parseDouble(args[3]);
	    if (probRandomSeg + probVertexToVertex > 1) {
		System.err.println("probabilities must add to <= 1");
		System.exit(1);
	    }
	    probExtend = Double.parseDouble(args[4]);
	    if (probExtend > 1) {
		System.err.println("probExtend probability must be <= 1");
		System.exit(1);
	    }
	    gssFile = args[5];
	    matrixFile = args[6];
	    vertexFile = args[7];
	}
	    
	// create first line segment
	addSegmentAndIntersections( randomSegment(gridsize),
		linesegs, intersections, intersectionsList);

	// create 3 more random intersecting line segs to allow VertToVert
	for(int j = 1; j<4 && j<segnum; j++){
	    addSegmentAndIntersections(
		randomIntersectingSegment(linesegs, gridsize),
		linesegs, intersections, intersectionsList);
	}

	// continue until fully populated
	// INVAR: i = number of line segments generated so far
	for(int i = 4; i<segnum; i++){
	    double createType = Math.random();

	    if(createType <= probRandomSeg){
		// 0 <= createType <= probRandomSeg 
		addSegmentAndIntersections(
		    randomIntersectingSegment(linesegs, gridsize),
		    linesegs, intersections, intersectionsList);
	    } else if(createType <= probRandomSeg + probVertexToVertex){
		// probRandomSeg < createType <=
		//	probRandomSeg + probVertexToVertex
		LineSegment seg
		    = vertexToVertex(intersectionsList, linesegs);
		// vertexToVertex has a chance of failing, hence this test
		if (seg == null) {
		    seg = randomIntersectingSegment(linesegs, gridsize);
		} else {
		    seg = probExtendSegment (probExtend, 3, seg,
			    linesegs, gridsize);
		}
		addSegmentAndIntersections(seg, linesegs,
			intersections, intersectionsList);
	    } else{
		// probRandomSeg + probVertexToVertex < createType <= 1
		// probVertexToRandom
		//  = 1 - (probRandomSeg + probVertexToVertex)
		addSegmentAndIntersections(
			probExtendSegment(probExtend, 1, 
			    randomVertexToRandom(
				intersectionsList, linesegs, gridsize),
			    linesegs,
			    gridsize),
			linesegs, intersections, intersectionsList);
	    }
	}
	
	// set vertex visibilities
	for(Map.Entry<Vertex, ? extends Set<LineSegment> > e
		: intersections.entrySet())
	{
	    Vertex v = e.getKey();
	    v.setVisibility(new HashSet<LineSegment>(e.getValue()));
	}

	writeFiles(linesegs, intersections.keySet(),
		gssFile, matrixFile, vertexFile);

    }//end main

}//end class
